package com.easylinkin.linkappapi.jkmonior.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.common.utils.excel.ExcelConstant;
import com.easylinkin.linkappapi.common.utils.excel.ExcelTools;
import com.easylinkin.linkappapi.common.utils.io.OutputStreamUtil;
import com.easylinkin.linkappapi.jkmonior.entity.JkMonitorConfig;
import com.easylinkin.linkappapi.jkmonior.entity.JkMonitorItemConfig;
import com.easylinkin.linkappapi.jkmonior.entity.vo.JkConfigVo;
import com.easylinkin.linkappapi.jkmonior.entity.vo.JkItemConfigChildrenVo;
import com.easylinkin.linkappapi.jkmonior.entity.vo.JkMonitorItemConfigVo;
import com.easylinkin.linkappapi.jkmonior.mapper.JkMonitorConfigMapper;
import com.easylinkin.linkappapi.jkmonior.mapper.JkMonitorItemConfigMapper;
import com.easylinkin.linkappapi.jkmonior.service.JkMonitorItemConfigService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import site.morn.rest.RestBuilders;
import site.morn.rest.RestMessage;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.*;

/**
 * JkMonitorItemConfig表服务实现类
 *
 * @author zhengwen
 * @date 2022/10/28
 */
@Slf4j
@Service("appJkMonitorItemConfigService")
public class JkMonitorItemConfigServiceImpl extends ServiceImpl
        <JkMonitorItemConfigMapper, JkMonitorItemConfig> implements JkMonitorItemConfigService {
    @Resource
    private CommonService commonService;
    @Resource
    private LinkappUserContextProducer linkappUserContextProducer;

    @Resource
    private JkMonitorConfigMapper jkMonitorConfigMapper;

    @Override
    public boolean saveOne(JkMonitorItemConfig appJkMonitorItemConfig) {
        commonService.setCreateAndModifyInfo(appJkMonitorItemConfig);
        // appJkMonitorItemConfig.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        validParamRequired(appJkMonitorItemConfig);
        validRepeat(appJkMonitorItemConfig);
        validParamFormat(appJkMonitorItemConfig);
        return save(appJkMonitorItemConfig);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOne(JkMonitorItemConfig appJkMonitorItemConfig) {
        Assert.notNull(appJkMonitorItemConfig.getId(), "id不能为空");
        commonService.setModifyInfo(appJkMonitorItemConfig);
        //appJkMonitorItemConfig.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        validRepeat(appJkMonitorItemConfig);
        validParamFormat(appJkMonitorItemConfig);
        return updateById(appJkMonitorItemConfig);
    }

    @Override
    public IPage<JkMonitorItemConfig> selectPage(Page page, JkMonitorItemConfig appJkMonitorItemConfig) {
        //appJkMonitorItemConfig.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        return baseMapper.selectPage(page, appJkMonitorItemConfig);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteByIds(List<Long> idList) {
        return removeByIds(idList);
    }

    @Override
    public void export(JkMonitorItemConfig appJkMonitorItemConfig, HttpServletRequest request, HttpServletResponse
            response) {

        IPage<JkMonitorItemConfig> page = selectPage(new Page(0, -1), appJkMonitorItemConfig);
        List<JkMonitorItemConfig> records = page.getRecords();
        List
                <JkMonitorItemConfigVo> appJkMonitorItemConfigVos = new ArrayList<>();
        for (JkMonitorItemConfig expert : records) {
            appJkMonitorItemConfigVos.add(new JkMonitorItemConfigVo(expert));
        }

        String keyValue = "名称:name,租户id:tenantId";
        String title = "JkMonitorItemConfig导出数据";
        String fileName = title + ".xls";
        try {
            OutputStream outputStream = OutputStreamUtil
                    .getOutputStream(request, response, fileName);
            ExcelTools.exportExcel(outputStream, keyValue, appJkMonitorItemConfigVos, ExcelConstant.XLS, title);
            response.flushBuffer();
            outputStream.close();
        } catch (IOException e) {
            log.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！IOException异常" + e.getMessage());
        } catch (Exception e) {
            log.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！" + e.getMessage());
        }
    }

    @Override
    public RestMessage getMonitorItemConfig(JkMonitorItemConfigVo jkMonitorItemConfigVo) {
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        String tenantId = linkappUser.getTenantId();

        JkConfigVo vo = new JkConfigVo();

        //查询配置基本信息
        QueryWrapper<JkMonitorConfig> configQw = new QueryWrapper<>();
        configQw.eq("tenant_id", tenantId);
        configQw.eq("delete_state", 1);
        configQw.orderByDesc("create_time");
        configQw.last(" limit 1");
        List<JkMonitorConfig> configList = jkMonitorConfigMapper.selectList(configQw);
        if (CollectionUtil.isNotEmpty(configList)) {
            JkMonitorConfig config = configList.get(0);
            vo.setConfig(config);

            //查询测项目、点信息
            QueryWrapper<JkMonitorItemConfig> itemQw = new QueryWrapper<>();
            itemQw.eq("tenant_id", tenantId);
            itemQw.eq("delete_state", 1);
            List<JkMonitorItemConfig> itemList = baseMapper.selectList(itemQw);

            vo.setItemConfig(itemList);
        }

        return RestBuilders.successBuilder().data(vo).build();
    }

    @Override
    public RestMessage syncMonitorItem(JkMonitorItemConfigVo jkMonitorItemConfigVo) {
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        String tenantId = linkappUser.getTenantId();

        //组织成这个格式
        JkConfigVo vo = new JkConfigVo();
        //查询基本配置
        QueryWrapper<JkMonitorConfig> configQw = new QueryWrapper<>();
        configQw.eq("tenant_id", tenantId);
        configQw.eq("delete_state", 1);
        configQw.orderByDesc("create_time");
        configQw.last(" limit 1");
        List<JkMonitorConfig> configList = jkMonitorConfigMapper.selectList(configQw);
        if (CollectionUtil.isNotEmpty(configList)) {
            JkMonitorConfig config = configList.get(0);
            vo.setConfig(config);

            List<JkMonitorItemConfig> finItemList = new ArrayList<>();
            //查询现有最新监测项点信息
            //查询测项目、点信息
            QueryWrapper<JkMonitorItemConfig> itemQw = new QueryWrapper<>();
            itemQw.eq("tenant_id", tenantId);
            itemQw.eq("delete_state", 1);
            List<JkMonitorItemConfig> itemList = baseMapper.selectList(itemQw);
            Map<String, JkMonitorItemConfig> mp = new HashMap<>();
            if (CollectionUtil.isNotEmpty(itemList)) {
                //转map
                itemList.stream().forEach(ic -> {
                    String name = ic.getItemName();
                    String code = ic.getItemCode();
                    Integer type = ic.getItemType();
                    String key = type.intValue() + "," + code + "," + name;
                    mp.put(key, ic);
                });
            }
            //组织Url查询返回数据(目前这个第三方是这样，后面这里可能需要增加一层适配)
            JSONArray dataArray = getNewRecordList(config);
            if (CollectionUtil.isNotEmpty(dataArray)) {
                for (int i = 0;i < dataArray.size();i++) {
                    JSONObject jc = JSONUtil.parseObj(dataArray.get(i));
                    JkMonitorItemConfig typeConfig = converMonitorItemConfig(jc, config, null,i);
                    if (typeConfig != null) {
                        //判断原先是否有
                        JkMonitorItemConfig oldType = getDbItemConfig(typeConfig,mp);
                        finItemList.add(oldType);
                        JSONArray childrenJsonArr = jc.getJSONArray("children");
                        if (CollectionUtil.isNotEmpty(childrenJsonArr)){
                            for (int j = 0;j < childrenJsonArr.size();j++) {
                                JSONObject jd = JSONUtil.parseObj(childrenJsonArr.get(j));
                                JkMonitorItemConfig itemConfig = converMonitorItemConfig(jd, config, oldType,j);
                                JkMonitorItemConfig oldItem = getDbItemConfig(itemConfig,mp);
                                finItemList.add(oldItem);
                            }
                        }

                    }
                }
            }
            vo.setItemConfig(finItemList);
        }

        return RestBuilders.successBuilder().data(vo).build();
    }

    @Override
    public RestMessage saveMonitorItemConfig(JkConfigVo jkConfigVo) {
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        String tenantId = linkappUser.getTenantId();

        JkMonitorConfig config = jkConfigVo.getConfig();

        Date now = DateUtil.date();
        //查询基本配置
        QueryWrapper<JkMonitorConfig> configQw = new QueryWrapper<>();
        configQw.eq("tenant_id", tenantId);
        configQw.eq("delete_state", 1);
        configQw.orderByDesc("create_time");
        List<JkMonitorConfig> configList = jkMonitorConfigMapper.selectList(configQw);
        if (CollectionUtil.isNotEmpty(configList)) {
            configList.stream().forEach(c->{
                c.setJkImg(config.getJkImg());
                c.setModifier(linkappUser.getId().toString());
                c.setModifyTime(now);
                jkMonitorConfigMapper.updateById(c);
            });
        }

        //直接先删除原先所有的，再重新保存
        QueryWrapper<JkMonitorItemConfig> itemQw = new QueryWrapper<>();
        itemQw.eq("tenant_id", tenantId);
        baseMapper.delete(itemQw);
        //再重新保存
        List<JkItemConfigChildrenVo> itemChildrenConfig = jkConfigVo.getItemChildrenConfig();
        if (CollectionUtil.isNotEmpty(itemChildrenConfig)){
            //保存的数据的快照
            Map<String,JkMonitorItemConfig> inMp = new HashMap<>();
            itemChildrenConfig.stream().forEach(t->{
                iteratorSaveItem(t,linkappUser,inMp);
            });
        }

        return RestBuilders.successBuilder().build();
    }

    /**
     * 迭代存储测点
     * @param t 测点信息
     * @param linkappUser 租户信息
     * @param inMp 辅助对象
     */
    private void iteratorSaveItem(JkItemConfigChildrenVo t, LinkappUser linkappUser, Map<String, JkMonitorItemConfig> inMp) {
        //String key = t.getItemType().intValue() + "," + t.getItemCode() + "," + t.getItemName();
        String key = t.getId().toString();
        JkMonitorItemConfig ic = initItemConfig(t,linkappUser,inMp);
        baseMapper.insert(ic);
        inMp.put(key,ic);
        List<JkItemConfigChildrenVo> childrenVoList = t.getChildren();
        if (CollectionUtil.isNotEmpty(childrenVoList)){
            childrenVoList.stream().forEach(c->{
                iteratorSaveItem(c,linkappUser,inMp);
            });
        }
    }

    private JkMonitorItemConfig initItemConfig(JkMonitorItemConfig t, LinkappUser linkappUser, Map<String, JkMonitorItemConfig> inMp) {
        String key = t.getId().toString();
        Integer parentId = t.getParentId();
        JkMonitorItemConfig inParent = inMp.get(parentId.toString());
        JkMonitorItemConfig ic = new JkMonitorItemConfig();
        BeanUtil.copyProperties(t,ic, CopyOptions.create().setIgnoreNullValue(true));
        ic.setId(null);
        ic.setCreator(linkappUser.getId().toString());
        ic.setCreateTime(DateUtil.date());
        ic.setModifier(ic.getCreator());
        ic.setModifyTime(ic.getCreateTime());
        Integer type = t.getItemType();
        if (type.intValue() == 1){
            //测项目
            ic.setParentIds(",0,");
            ic.setParentId(0);
        }else{
            //测点
            if(inParent != null){
                ic.setParentIds(inParent.getParentIds() + inParent.getId() + ",");
                ic.setParentId(inParent.getId());
            }
        }
        return ic;
    }

    /**
     * 比对原测项、点配置
     * @param typeConfig 项点配置
     * @param mp 项点配置map
     * @return 项点配置
     */
    private JkMonitorItemConfig getDbItemConfig(JkMonitorItemConfig typeConfig, Map<String, JkMonitorItemConfig> mp) {
        String key = typeConfig.getItemType().intValue() + "," + typeConfig.getItemCode() + "," + typeConfig.getItemName();
        JkMonitorItemConfig oldItem = mp.get(key);
        if (oldItem != null){
            typeConfig = oldItem;
        }
        return typeConfig;
    }

    /**
     * 根据基础配置从第三方获取最新项点数据
     * @param config 基础配置
     * @return 项点json数组数据
     */
    private JSONArray getNewRecordList(JkMonitorConfig config) {
        String monitorDataUrl = config.getDataMonitorUrl();
        cn.hutool.core.lang.Assert.isTrue(StringUtils.isNotBlank(monitorDataUrl), "基坑监测数据url为空");

        String projectId = config.getProjectId();
        cn.hutool.core.lang.Assert.isTrue(StringUtils.isNotBlank(projectId), "基坑所属项目ID为空");

        if (monitorDataUrl.indexOf(projectId) < 0) {
            if (monitorDataUrl.endsWith("=")) {
                monitorDataUrl += projectId;
            } else {
                if(!monitorDataUrl.contains(projectId)){
                    monitorDataUrl += "&projectId=" + projectId;
                }
            }
        }
        //从第三方获取数据
        String dataStr = HttpUtil.get(monitorDataUrl);
        if (JSONUtil.isJson(dataStr)) {
            JSONObject resultJson = JSONUtil.parseObj(dataStr);
            JSONArray dataArray = resultJson.getJSONArray("data");
            return dataArray;
        }
        return null;
    }

    /**
     * 转换项点配置
     * @param dataJson 获取到的项点json
     * @param config 基础配置
     * @param parent 父级项点
     * @param i 序号
     * @return 项点配置
     */
    private JkMonitorItemConfig converMonitorItemConfig(JSONObject dataJson, JkMonitorConfig config, JkMonitorItemConfig parent, int i) {
        //虚拟的id从9百万开始，应该是够用的了
        Integer initMaxId = 9000000;
        JkMonitorItemConfig jkMonitorItemConfig = new JkMonitorItemConfig();

        if (config != null) {
            jkMonitorItemConfig.setTenantId(config.getTenantId());
        }
        if (parent == null) {
            jkMonitorItemConfig.setItemType(1);
            jkMonitorItemConfig.setParentId(0);
            jkMonitorItemConfig.setItemName(dataJson.getStr("measurement_project_name"));
            jkMonitorItemConfig.setId(initMaxId + i);
        } else {
            jkMonitorItemConfig.setItemType(2);
            jkMonitorItemConfig.setParentId(parent.getId());
            jkMonitorItemConfig.setItemName(dataJson.getStr("point_name"));
            jkMonitorItemConfig.setId(parent.getId() * 100 + i);
        }
        jkMonitorItemConfig.setItemCode(dataJson.getStr("point_name"));

        jkMonitorItemConfig.setDeleteState(1);
        return jkMonitorItemConfig;
    }

    @Override
    public JkMonitorItemConfig getOneById(Serializable id) {
        return baseMapper.getOneById(id);
    }

    /**
     * 校验重复
     */
    private void validRepeat(JkMonitorItemConfig appJkMonitorItemConfig) {
        /* QueryWrapper<JkMonitorItemConfig> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", appJkMonitorItemConfig.getName());
        queryWrapper.eq("tenant_id", linkappUserContextProducer.getNotNullCurrent().getTenantId());
        List<JkMonitorItemConfig> list = baseMapper.selectList(queryWrapper);
        if (list.size() == 0) {
            return;
        }
        if (list.size() > 1) {
            throw new BusinessException("名称有重复");
        }
        if (ObjectUtils.isEmpty(appJkMonitorItemConfig.getId())) {
            throw new BusinessException("名称已存在");
        }
        if (!appJkMonitorItemConfig.getId().equals(list.get(0).getId())) {
            throw new BusinessException("名称已存在");
        }
                    */

    }


    /**
     * 校验参数必填
     */
    private void validParamRequired(JkMonitorItemConfig appJkMonitorItemConfig) {
        //Assert.notNull(appJkMonitorItemConfig, "参数为空");
        //Assert.isTrue(StringUtils.isNotBlank(appJkMonitorItemConfig.getName()), "名称为空");
    }

    /**
     * 校验参数格式
     */
    private void validParamFormat(JkMonitorItemConfig appJkMonitorItemConfig) {
        //Assert.isTrue(appJkMonitorItemConfig.getName() == null || appJkMonitorItemConfig.getName().length() <= 50,
        //        "名称超长");
    }
}

